/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
 * ubs-engine is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include "test_ubse_cli_reg.h"
#include <mockcpp/mockcpp.hpp>
#include "ubse_cli_reg.h"
#include "ubse_cli_reg_builder.h"

namespace ubse::ut::cli {
using namespace ubse::cli::reg;
using namespace ubse::cli::framework;

void TestUbseCliReg::SetUp() {}

void TestUbseCliReg::TearDown() {}

std::shared_ptr<UbseCliResultEcho> UbseCliTestFun([[maybe_unused]] const std::map<std::string, std::string> &params)
{
    return std::make_shared<UbseCliStringEcho>("Hello Ub!");
}

TEST_F(TestUbseCliReg, RegNormal)
{
    std::vector<UbseCliOptionsInfo> params_infos;
    params_infos.push_back({ "t1", "test1", "this is option test1" });
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    UbseCliRegBuilder builder;
    cmd_reg_info.push_back({ "command1", "type1", params_infos, UbseCliTestFun });
    cmd_reg_info.push_back({ "command2", "type2", {}, UbseCliTestFun });
    cmd_reg_info.push_back({ "command3", "type3", {}, UbseCliTestFun });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    auto flag = UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse(
        { "command1", "type1", "-t1", "test" });
    EXPECT_TRUE(flag);
    flag = UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse({ "command2", "type2" });
    EXPECT_TRUE(flag);
    flag = UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse({ "command3", "type3" });
    EXPECT_TRUE(flag);
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, RegInfoNull)
{
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    ASSERT_NO_THROW(UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info));
}

TEST_F(TestUbseCliReg, RegInfoMissing)
{
    std::vector<UbseCliOptionsInfo> params_infos;
    params_infos.push_back({ "t1", "test1", "this is option test1" });
    std::vector<UbseCliOptionsInfo> params_infos_without_cmd;
    params_infos_without_cmd.push_back({ "", "test1", "this is option test1" });
    std::vector<UbseCliOptionsInfo> params_infos_without_type;
    params_infos_without_type.push_back({ "t1", "", "this is option test1" });
    std::vector<UbseCliOptionsInfo> params_infos_without_desc;
    params_infos_without_desc.push_back({ "t1", "test1", "" });
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    cmd_reg_info.push_back({ "command1", "type1", {}, UbseCliTestFun });
    cmd_reg_info.push_back({ "command2", "type2", params_infos, UbseCliTestFun });
    cmd_reg_info.push_back({ "command3", "type3", params_infos_without_cmd, UbseCliTestFun });
    cmd_reg_info.push_back({ "command4", "type4", params_infos_without_type, UbseCliTestFun });
    cmd_reg_info.push_back({ "command5", "type5", params_infos_without_desc, UbseCliTestFun });
    cmd_reg_info.push_back({ "", "type6", params_infos, UbseCliTestFun });
    cmd_reg_info.push_back({ "command7", "", params_infos, UbseCliTestFun });
    cmd_reg_info.push_back({ "command8", "type8", params_infos, nullptr });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    auto flag = UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse({ "command1", "type1" });
    EXPECT_TRUE(flag);
    flag = UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse({ "command2", "type2" });
    EXPECT_TRUE(flag);
    flag = UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse({ "command3", "type3" });
    EXPECT_FALSE(flag);
    flag = UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse({ "command4", "type4" });
    EXPECT_FALSE(flag);
    flag = UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse({ "command5", "type5" });
    EXPECT_FALSE(flag);
    flag = UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse({ "command6", "type6" });
    EXPECT_FALSE(flag);
    flag = UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse({ "command7", "type7" });
    EXPECT_FALSE(flag);
    flag = UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse({ "command8", "type8" });
    EXPECT_FALSE(flag);
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, RegInfoCmdTooLong)
{
    std::string command = "command1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    std::string command_normal = "command1";
    std::string type = "type1";
    std::vector<UbseCliOptionsInfo> params_infos;
    params_infos.push_back({ "t1", "test1", "this is option test1" });
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    cmd_reg_info.push_back({ command, type, params_infos, UbseCliTestFun });
    cmd_reg_info.push_back({ command_normal, type, params_infos, UbseCliTestFun });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    auto flag = UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse({ command, type });
    EXPECT_FALSE(flag);
    flag = UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse({ command_normal, type });
    EXPECT_TRUE(flag);
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, RegInfoTypeTooLong)
{
    std::string command = "command1";
    std::string type = "type1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    std::string type_normal = "type1";
    std::vector<UbseCliOptionsInfo> params_infos;
    params_infos.push_back({ "t1", "test1", "this is option test1" });
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    cmd_reg_info.push_back({ command, type, params_infos, UbseCliTestFun });
    cmd_reg_info.push_back({ command, type_normal, params_infos, UbseCliTestFun });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    auto flag = UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse({ command, type });
    EXPECT_FALSE(flag);
    flag = UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse({ command, type_normal });
    EXPECT_TRUE(flag);
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, RegInfoOptTooLong)
{
    std::string command = "command1";
    std::string type = "type1";
    std::vector<UbseCliOptionsInfo> params_infos;
    params_infos.push_back(
        { "t1", "longnamexxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "this is option test1" });
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    cmd_reg_info.push_back({ command, type, params_infos, UbseCliTestFun });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    auto flag = UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse({ command, type });
    EXPECT_FALSE(flag);
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, RegInfoOptNumExceeds)
{
    std::string command = "command1";
    std::string type = "type1";
    std::vector<UbseCliOptionsInfo> params_infos;
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    params_infos.reserve(16);
    for (int i = 0; i < 16; ++i) {
        params_infos.push_back({ "t1" + std::to_string(i), "test1" + std::to_string(i), "this is option test1" });
    }
    cmd_reg_info.push_back({ command, type, params_infos, UbseCliTestFun });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    auto flag = UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse({ command, type });
    EXPECT_FALSE(flag);
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, RegCmdInfoNumExceeds)
{
    std::string command = "command1";
    std::string type = "type1";
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    cmd_reg_info.reserve(32);
    for (int i = 0; i < 32; ++i) {
        cmd_reg_info.push_back({ "command1" + std::to_string(i), "type1", {}, UbseCliTestFun });
    }
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    EXPECT_EQ(UbseCliModuleRegistry::GetInstance().fullCommandInfo.size(), 0);
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, OneCommandHelpInfo)
{
    std::vector<UbseCliOptionsInfo> params_infos;
    params_infos.push_back({ "t1", "test1", "this is option test1" });
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    cmd_reg_info.push_back({ "command1", "type1", params_infos, UbseCliTestFun });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    EXPECT_EQ(UbseCliModuleRegistry::GetInstance().fullCommandInfo.size(), 1);
    EXPECT_TRUE(UbseCliModuleRegistry::GetInstance().UbseCliHelpInfoParse({ "command1", "type1", "-h" }));
    EXPECT_TRUE(UbseCliModuleRegistry::GetInstance().UbseCliHelpInfoParse({ "command1", "type1", "--help" }));
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, AllCommandsHelpInfo)
{
    std::vector<UbseCliOptionsInfo> params_infos;
    params_infos.push_back({ "t1", "test1", "this is option test1" });
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    cmd_reg_info.push_back({ "command1", "type1", params_infos, UbseCliTestFun });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    std::vector<std::string> args{};
    EXPECT_TRUE(UbseCliModuleRegistry::GetInstance().UbseCliHelpInfoParse(args));
    args = { "--help" };
    EXPECT_TRUE(UbseCliModuleRegistry::GetInstance().UbseCliHelpInfoParse(args));
    args = { "display", "--help" };
    EXPECT_TRUE(UbseCliModuleRegistry::GetInstance().UbseCliHelpInfoParse(args));
    args = { "display", "info", "--help" };
    EXPECT_TRUE(UbseCliModuleRegistry::GetInstance().UbseCliHelpInfoParse(args));
    args = { "command1", "type1", "--help" };
    EXPECT_TRUE(UbseCliModuleRegistry::GetInstance().UbseCliHelpInfoParse(args));
    args = { "command1", "type1", "another", "--help" };
    EXPECT_TRUE(UbseCliModuleRegistry::GetInstance().UbseCliHelpInfoParse(args));
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, GetMappingCmd)
{
    std::vector<UbseCliOptionsInfo> params_infos;
    params_infos.push_back({ "t1", "test1", "this is option test1" });
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    cmd_reg_info.push_back({ "command1", "type1", params_infos, UbseCliTestFun });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    std::vector<std::string> args = { "command1", "type1" };
    EXPECT_TRUE(UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse(args));
    EXPECT_EQ(UbseCliModuleRegistry::GetInstance().UbseCliGetMatchCommand().command, "command1");
    EXPECT_EQ(UbseCliModuleRegistry::GetInstance().UbseCliGetMatchCommand().type, "type1");
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, CmdNotExit)
{
    std::vector<UbseCliOptionsInfo> params_infos;
    params_infos.push_back({ "t1", "test1", "this is option test1" });
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    cmd_reg_info.push_back({ "command1", "type1", params_infos, UbseCliTestFun });
    cmd_reg_info.push_back({ "command2", "type2", {}, UbseCliTestFun });
    cmd_reg_info.push_back({ "command3", "type3", {}, UbseCliTestFun });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    std::vector<std::string> args{ "command4", "type1" };
    EXPECT_FALSE(UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse(args));
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, GetInputOptValMap)
{
    std::vector<UbseCliOptionsInfo> params_infos;
    params_infos.push_back({ "t1", "test1", "this is option test1" });
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    cmd_reg_info.push_back({ "command1", "type1", params_infos, UbseCliTestFun });
    cmd_reg_info.push_back({ "command2", "type2", {}, UbseCliTestFun });
    cmd_reg_info.push_back({ "command3", "type3", {}, UbseCliTestFun });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    std::vector<std::string> args{ "command1", "type1", "--test1", "aaa" };
    EXPECT_TRUE(UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse(args));
    auto info = UbseCliModuleRegistry::GetInstance().UbseCliGetMatchCommand();
    EXPECT_EQ(info.command, "command1");
    EXPECT_EQ(info.type, "type1");
    auto infoMap = UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliGetInputOptionMap();
    EXPECT_EQ(infoMap.find("test1")->second, "aaa");
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, InputOptMapValNotExit)
{
    std::vector<UbseCliOptionsInfo> params_infos;
    params_infos.push_back({ "t1", "test1", "this is option test1" });
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    cmd_reg_info.push_back({ "command1", "type1", params_infos, UbseCliTestFun });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    std::vector<std::string> args{ "command4", "type1", "-t1", "aaa" };
    EXPECT_FALSE(UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse(args));
    EXPECT_EQ(0, UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliGetInputOptionMap().size());
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, InputInvalidOptVal)
{
    std::vector<UbseCliOptionsInfo> params_infos;
    params_infos.push_back({ "t1", "test1", "this is option test1" });
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    cmd_reg_info.push_back({ "command1", "type1", params_infos, UbseCliTestFun });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    std::vector<std::string> args{ "command1", "type1", "t2", "aaa" };
    EXPECT_FALSE(UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse(args));
    EXPECT_EQ(0, UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliGetInputOptionMap().size());
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, InputDupOptVal)
{
    std::vector<UbseCliOptionsInfo> params_infos;
    params_infos.push_back({ "t1", "test1", "this is option test1" });
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    cmd_reg_info.push_back({ "command1", "type1", params_infos, UbseCliTestFun });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    std::vector<std::string> args{ "command1", "type1", "-t1", "aaa", "--test1", "aaa" };
    EXPECT_FALSE(UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse(args));
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, InputOptNoVal)
{
    std::vector<UbseCliOptionsInfo> params_infos;
    params_infos.push_back({ "t1", "test1", "this is option test1" });
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    cmd_reg_info.push_back({ "command1", "type1", params_infos, UbseCliTestFun });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    std::vector<std::string> args{ "command1", "type1", "-t1" };
    EXPECT_FALSE(UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse(args));
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, InputUnkonwOpt)
{
    std::vector<UbseCliOptionsInfo> params_infos;
    params_infos.push_back({ "t1", "test1", "this is option test1" });
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    cmd_reg_info.push_back({ "command1", "type1", params_infos, UbseCliTestFun });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    std::vector<std::string> args{ "rack-cli", "command1", "type1", "-t2", "aaa" };
    EXPECT_FALSE(UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse(args));
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, InputOptionMapNoOpt)
{
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    cmd_reg_info.push_back({ "command1", "type1", {}, UbseCliTestFun });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    std::vector<std::string> args{ "command1", "type1", "-t1", "aaa" };
    EXPECT_FALSE(UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse(args));
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, InputOptionMapNoOptSuccess)
{
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    cmd_reg_info.push_back({ "command1", "type1", {}, UbseCliTestFun });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    std::vector<std::string> args{ "command1", "type1" };
    EXPECT_TRUE(UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse(args));
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}

TEST_F(TestUbseCliReg, InputTooLongValue)
{
    std::vector<UbseCliOptionsInfo> params_infos;
    params_infos.push_back({ "t1", "test1", "this is option test1" });
    std::vector<UbseCliCommandInfo> cmd_reg_info;
    cmd_reg_info.push_back({ "command1", "type1", params_infos, UbseCliTestFun });
    UbseCliModuleRegistry::GetInstance().UbseCliRegister(cmd_reg_info);
    std::vector<std::string> args{ "command1", "type1", "-t1", std::string("a", 1025) };
    EXPECT_FALSE(UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliArgsParse(args));
    UbseCliModuleRegistry::GetInstance().UbseCliReset();
    UbseCliModuleRegistry::GetInstance().UbseCliGetParseTool().UbseCliReset();
}
} // namespace ubse::ut::cli
